package poc.spring.xml;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;

import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class DomParser {
	Document doc;
	String origXml;

	public ArrayList<String> parseXmlFile(String xmlSrc, NamespaceContext context, String xpathExpression) {
		ArrayList<String> fragmentNodes = new ArrayList<String>();
		if (xmlSrc.length() <= 0) {
			System.out.println("XML SOURCE IS EMPTY");
		}
		
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			factory.setNamespaceAware(true); // never forget this!
			DocumentBuilder builder = factory.newDocumentBuilder();

			InputSource source = new InputSource();
			source.setCharacterStream((new StringReader(xmlSrc)));

			// parse using builder to get DOM representation of the XML file
			doc = builder.parse(source);
			
			XPathFactory xFactory = XPathFactory.newInstance();
			XPath xpath = xFactory.newXPath();
			xpath.setNamespaceContext(context);
			XPathExpression expr = xpath.compile(xpathExpression);
			Object result = expr.evaluate(doc, XPathConstants.NODESET);
			  
			NodeList nodes = (NodeList) result;			
			for (int i = 0; i < nodes.getLength(); i++) {
//				System.out.println("nodes length: " + nodes.getLength());
				
				NodeList childNodes = nodes.item(i).getChildNodes();
//				System.out.println("childNodes length: " + childNodes.getLength());
				
				for (int j = 0; j < childNodes.getLength(); j++) {
					String currentNode = xmlFragmentAsString(childNodes.item(j)); 
//					System.out.println( currentNode );
					if ( currentNode.length() > 0 ) {
						fragmentNodes.add(currentNode);
					}
				} 
			  }
			
			for (String xmlFrag : fragmentNodes) {
				System.out.println("Node: \n" + xmlFrag);
			}
			
		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
		} catch (SAXException se) {
			se.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}		

		return fragmentNodes;
	}
	
	
	public String xmlFragmentAsString(Node node) {
		String str = "";
		try {
			TransformerFactory transFactory = TransformerFactory.newInstance();
			StringWriter buffer = new StringWriter();			
			
			Transformer transformer = transFactory.newTransformer();
			transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
			transformer.transform(new DOMSource(node), new StreamResult(buffer));

			str = buffer.toString().trim();
			
		} catch (TransformerConfigurationException tce) {
			tce.printStackTrace();
		} catch (TransformerException tfe) {
			tfe.printStackTrace();
		}

		return str;
	}

	
	public Document parseXmlFile(String xmlSrc, NamespaceContext context) {
		if (xmlSrc.length() <= 0) {
			System.out.println("XML SOURCE IS EMPTY");
		}
		
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			factory.setNamespaceAware(true); // never forget this!
			DocumentBuilder builder = factory.newDocumentBuilder();

			InputSource source = new InputSource();
			source.setCharacterStream((new StringReader(xmlSrc)));

			// parse using builder to get DOM representation of the XML file
			doc = builder.parse(source);
			
		} catch (ParserConfigurationException pce) {
			pce.printStackTrace();
		} catch (SAXException se) {
			se.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}

		return doc;
	}
}
